﻿using CommonModel.Field;
using CommonModel.Model;
using NewLife.Log;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml;
using static CommonModel.Model.DataTypeDll;

namespace PtlSvr.CfgLoader.Schema
{
    class SchemaParseByConfig
    {

        public SchemaDocument parse(string xml)
        {
            SchemaDocument schemaDocument = new SchemaDocument();
            Dictionary<string, string> dynamicParaDictionary = new Dictionary<string, string>();

            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
            XmlDocument doc = new XmlDocument();
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;//忽略文档里面的注释
            // 根据一级指标map, 顺序解析xml
            Dictionary<int, Object> schema = new Dictionary<int, Object>();
            try
            {
                XmlReader reader = XmlReader.Create(xml, settings);
                doc.Load(reader);
                XmlNode rootEle = doc.SelectSingleNode("schema");//获得根节点
                XmlElement xe = (XmlElement)rootEle;//将节点转为元素
                string name = xe.GetAttribute("name");//得到节点元素的属性值
                schemaDocument.setName(name);
                schemaDocument.setFile_name(xml.Substring(xml.LastIndexOf("/") + 1));
                string msgType = xe.GetAttribute("msgType");
                schemaDocument.setMsgType(msgType);
                string xmlType = xe.GetAttribute("xmlType");
                schemaDocument.setXmlType(xmlType);
                XmlNodeList xn_child = rootEle.ChildNodes;//得到根节点的所有子节点

                Dictionary<int, XmlElement> fieldDictionary = new Dictionary<int, XmlElement>();
                // 生成所有一级指标map
                foreach (XmlNode xnc in xn_child)
                {
                    if (xnc is XmlElement)
                    {
                        XmlElement xec = (XmlElement)xnc;//将节点转换为元素
                        int id = Int32.Parse(xec.GetAttribute("index"));
                        //fieldDictionary.Add(id, xec);
                        DictAdd(fieldDictionary, id, xec);
                    }
                }

                // 对字段index进行排序, 以便顺序解析
                List<int> fieldOrderList = new List<int>(fieldDictionary.Keys);//把fieldDictionary的所有Key值放进list中
                fieldOrderList.Sort();


                for (int idx = 0; idx < fieldOrderList.ToArray().Length; idx++)
                {
                    XmlElement subElement = fieldDictionary[fieldOrderList[idx]];
                    // 递归解析element元素
                    if (null != subElement)
                    {
                        parseElement(schema, dynamicParaDictionary, idx, subElement, fieldOrderList[idx]);
                    }
                }
            }
            catch (Exception e)
            {
                XTrace.WriteLine(xml + " " + e.Message);
            }
            schemaDocument.setFieldDictionary(schema);//将已读取XML文件后的XML字段规则放进schemaDocument
            schemaDocument.setDynamicParaDictionary(dynamicParaDictionary);
            return schemaDocument;
        }

        private void parseElement(Dictionary<int, Object> schema, Dictionary<string, string> paraDictionary, int index, XmlElement element, int fieldIdx)
        {
            string fieldName = element.Name;//先获取到该节点的名字

            //以下是该节点的元素属性
            //int fieldIndex = Int32.Parse(element.GetAttribute("index"));
            int fieldIndex = fieldIdx;

            string strType = element.GetAttribute("type");
            DataType fieldType = DataTypeUtils.getType(strType.ToLower());

            string typeSize = element.GetAttribute("size");
            string deviceType = element.GetAttribute("deviceType");
            string isAlarm = element.GetAttribute("isAlarm").ToLower();
            string loop = element.GetAttribute("loop");
            string code = element.GetAttribute("code").ToLower();
            string modIndex = element.GetAttribute("model_index");//命令码结构的索引，非必填
            string memo = element.GetAttribute("memo");
            string desc = element.GetAttribute("desc");
            if (!"".Equals(desc))
            {
                memo = desc;
            }

            // 如果节点没有子节点, 解析字段
            if (element.ChildNodes.Count == 0)
            {
                FieldSchema field = new FieldSchema();
                // 必填
                field.setName(fieldName);
                field.setIndex(fieldIndex);
                field.setType(fieldType);
                field.setMemo(memo);
                // 非必填
                if (null != typeSize && !typeSize.Equals(""))
                {
                    field.setSize(Int32.Parse(typeSize));
                }
                else
                {
                    field.setSize(1);
                }

                if (null != deviceType && !deviceType.Equals(""))
                {
                    field.setDeviceType(deviceType);
                }

                if (null != isAlarm && isAlarm.Equals("true"))
                {
                    string alarmValue = element.GetAttribute("alarmValue");
                    string alarmName = element.GetAttribute("alarmName");
                    if (null != alarmValue && !alarmValue.Equals("") && null != alarmName && !alarmName.Equals(""))
                    {
                        field.setAlarm(true);
                        field.setAlarmName(alarmName);
                        field.setAlarmValue(alarmValue);
                    }
                }
                // 处理 loop 关联字段,即loop的值是某个变量，要取到这个变量名
                if (null != loop && !loop.Equals(""))
                {
                    // 正则表达式获取字段值
                    Regex regex = new Regex("\\$\\{(.*)\\}");
                    // 将字段记录到变量表
                    if (regex.IsMatch(loop))
                    {
                        loop = loop.Replace("${", "");
                        //string relateFieldName = loop.Replace("}", "");
                        loop = loop.Replace("}", "");
                        if (paraDictionary.ContainsKey(loop))
                        { 
                            paraDictionary.Add(loop, loop);
                        }
                    }

                    field.setLoop(loop);
                }

                if (null != code && !code.Equals(""))
                {
                    field.setCode(code);
                }

                schema.Add(index, field);
            }
            else
            {
                // 如果节点有子节点, 解析字段
                Dictionary<int, XmlElement> fieldDictionary = new Dictionary<int, XmlElement>();

                SchemaDictionary schDictionary = new SchemaDictionary();

                // 处理 loop 关联字段
                if (null != loop && !loop.Equals(""))
                {
                    // 正则表达式获取字段值
                    Regex regex = new Regex("\\$\\{(.*)\\}");
                    // 将字段记录到变量表
                    if (regex.IsMatch(loop))
                    {
                        loop = loop.Replace("${", "");
                        //string relateFieldName = loop.Replace("}", "");
                        loop = loop.Replace("}", "");
                        //paraDictionary.Add(loop, "");
                        if (paraDictionary.ContainsKey(loop))
                        {
                            paraDictionary.Add(loop, loop);
                        }
                    }

                    schDictionary.setLoop(loop);
                }
                // 必填
                schDictionary.setName(fieldName);
                schDictionary.setIndex(fieldIndex);
                schDictionary.setType(fieldType);
                schDictionary.setMemo(memo);
                // 非必填
                if (null != typeSize && !typeSize.Equals(""))
                {
                    schDictionary.setSize(Int32.Parse(typeSize));
                }
                else
                {
                    schDictionary.setSize(1);
                }

                // 2020/11/16 增加命令码结构的索引  model_index, 非必填
                if (null != modIndex && !modIndex.Equals(""))
                {
                    schDictionary.setIndex(Int32.Parse(modIndex));
                }

                if (null != deviceType && !deviceType.Equals(""))
                {
                    schDictionary.setDeviceType(deviceType);
                }

                if (null != isAlarm && isAlarm.Equals("true"))
                {
                    string alarmValue = element.GetAttribute("alarmValue");
                    string alarmName = element.GetAttribute("alarmName");
                    if (null != alarmValue && !alarmValue.Equals("") && null != alarmName && !alarmName.Equals(""))
                    {
                        schDictionary.setAlarm(true);
                        schDictionary.setAlarmName(alarmName);
                        schDictionary.setAlarmValue(alarmValue);
                    }
                }
                if (null != loop)
                {
                    schDictionary.setLoop(loop);
                }

                if (null != code && !code.Equals(""))
                {
                    schDictionary.setCode(code);
                }

                // 生成所有子级指标map
                foreach (XmlNode xn_child in element)
                {
                    if (xn_child is XmlElement)
                    {
                        XmlElement subElement = (XmlElement)xn_child;
                        int id = Int32.Parse(subElement.GetAttribute("index"));
                        //fieldDictionary.Add(id, subElement);
                        DictAdd(fieldDictionary, id, subElement);
                    }
                }

                // 对字段index进行排序, 以便顺序解析
                List<int> fieldOrderList = new List<int>(fieldDictionary.Keys);
                fieldOrderList.Sort();
                // 根据一级指标map, 顺序解析xml

                Dictionary<int, Object> subSchema = new Dictionary<int, Object>();

                for (int idx = 0; idx < fieldOrderList.ToArray().Length; idx++)
                {
                    XmlElement subElement = fieldDictionary[fieldOrderList[idx]];
                    // 递归解析element元素
                    if (null != subElement)
                    {
                        parseElement(subSchema, paraDictionary, idx, subElement, fieldOrderList[idx]);
                    }
                }

                schDictionary.setFieldDictionary(subSchema);
                schema.Add(index, schDictionary);
            }
        }

        private int DictAdd(Dictionary<int, XmlElement> dict, int key, XmlElement subElement)
        {
            while (dict.ContainsKey(key))
            {
                key++;
            }
            dict.Add(key, subElement);
            return key;
        }
    }
}
